package org.utils.ui.xml;

/**
 * @author Manuel EVENO
 * @version 1.3
 */

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 * This class provide parsing of XML data file, such as setup files, and produce output to a tree.<P>
 * use now SAX 2.0 interface (the Simple API for XML, by D.Megginson david@megginson.com) and Xerces
 * parser (xml.apache.org/xerces-j) from Apache Software Foundation (http://www.apache.org/)<P>
 */
public class XMLDataTreeNodeParser extends DefaultHandler {
    private XMLReader xr = null;
    private Locator locator = null;

    private XMLDataTreeNode parsingTreeResult = null;
    private XMLDataTreeNode currentNode = null;

    private boolean mElementLineInsertion = false;

    // Constructor
    public XMLDataTreeNodeParser()
    {
		// init : creating Xerces parser
		super();
		try {
		    xr = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
		} catch(Exception ex) {
		  System.err.println("\n\nImpossible de creer le parser SAX !");
		  System.err.println("verifier qu'un parseur xml est present dans le classpath");
		  System.exit(-1);
		}
		xr.setContentHandler(this);
		xr.setErrorHandler(this);
    }

    private XMLDataTreeNode parseInputSource(InputSource is, boolean pElementLineInsertion)
	    throws SAXException, IOException
    {
		mElementLineInsertion = pElementLineInsertion;
	
		xr.parse(is);   // the parsing process will build the resulting tree ...
	
		// removing virtual root
		XMLDataTreeNode root = (XMLDataTreeNode) parsingTreeResult.getChildren().get(0);
		parsingTreeResult = null;
		root.setFather(null);
		return root;
    }

    public XMLDataTreeNode parse(InputStream is, boolean pElementLineInsertion) throws SAXException, IOException
    {
		return parseInputSource(new InputSource(is), pElementLineInsertion);
    }

    public XMLDataTreeNode parse(InputStream is) throws SAXException, IOException
    {
		return parseInputSource(new InputSource(is), false);
    }

    public XMLDataTreeNode parse(Reader is, boolean pElementLineInsertion) throws SAXException, IOException
    {
		return parseInputSource(new InputSource(is), pElementLineInsertion);
    }

    public XMLDataTreeNode parse(Reader is) throws SAXException, IOException
    {
		return parseInputSource(new InputSource(is), false);
    }

    ////////////////////////////////////////////////////////////////////
    // Event handlers.
    ////////////////////////////////////////////////////////////////////

    public final static String LINENUMBER_ATT =	"_noLigne_";

    public void setDocumentLocator(Locator pLocator)
    {
		this.locator = pLocator;
    }

    public void startDocument ()
    {
		// creating the root of the tree
		currentNode = parsingTreeResult = new XMLDataTreeNode("<root of the XML Data tree>", null);
    }

    public void startElement (String uri, String name,
		  String qName, Attributes attributes)
	{
		XMLDataTreeNode newNode = new XMLDataTreeNode(name, currentNode);
		currentNode.addChild(newNode);
		currentNode = newNode;
	
		if (mElementLineInsertion)
		    currentNode.addAttribute(LINENUMBER_ATT , Integer.toString(locator.getLineNumber()));
	
		// process parsed attibutes ...
		for (int i=0; i<attributes.getLength(); i++)
		    currentNode.addAttribute(attributes.getLocalName(i), attributes.getValue(i));
    }

    public void characters (char ch[], int start, int length)
    {
		String charsStr = new String(ch, start, length)/*.replace('\n', ' ')*/.trim();
		if(charsStr.length() != 0)          // adding it only if not empty or space char filled
		     currentNode.setValue(charsStr);
    }

    public void endElement (String uri, String name, String qName)
    {
		currentNode = (XMLDataTreeNode) currentNode.getParent();
    }
}
